home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-09-16 | 36.4 KB | 1,043 lines | [TEXT/CCL2] |
- ;-*- Mode: Lisp; Package: CCL -*-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;MacTCP.Lisp
- ;Copyright © 1991 Apple Computer, Inc.
- ;
- ; TCP streams.
- ;
- ; OPEN-TCP-STREAM creates a stream that does its I/O through a TCP port.
- ;
-
- ; 04/28/93 mwp Release
- ; 01/22/93 bill Steve Weyer's fix to make stream-tyi return NIL at EOF.
- ; 06/05/92 bill remove (dbg length)
- ; 05/05/92 bill Narinder Singh's mods to add a timeout value for passive opens.
- ;-------------- 2.0
- ; 03/20/92 bill format string needed arg in (initialize-instance (binary-tcp-stream))
- ; 02/27/92 bill Derek's mods to ease subclassing of tcp-stream.
- ; ----------- 2.0f3
- ; 02/05/92 gb change record defs to more nearly match TCPPB.h, etc.
- ; 01/20/92 gb minimal support for binary i/o.
- ; 12/24/91 gb fix some bugs; look harder for the resolver.
- ;--------- 2.0b4
- ; 08/20/91 bill %get-cstr -> %get-cstring
- ; 05/20/91 gb Still needs work.
- ; 01/10/91 bill Remove LAP
- ; 05/08/90 gz Released
-
- (in-package :ccl)
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
- (export '(open-tcp-stream)))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;Definitions
-
- ;TCP csCodes
- (defconstant $ipctlGetAddr 15)
- (defconstant $TCPCreate 30)
- (defconstant $TCPPassiveOpen 31)
- (defconstant $TCPActiveOpen 32)
- (defconstant $TCPSend 34)
- (defconstant $TCPNoCopyRcv 35)
- (defconstant $TCPRcvBfrReturn 36)
- (defconstant $TCPRcv 37)
- (defconstant $TCPClose 38)
- (defconstant $TCPAbort 39)
- (defconstant $TCPStatus 40)
- (defconstant $TCPExtendedStat 41)
- (defconstant $TCPRelease 42)
- (defconstant $TCPGlobalInfo 43)
- (defconstant $TCPCtlMax 49)
-
- ;TCP event codes
- (defconstant $TCPClosing 1)
- (defconstant $TCPULPTimeout 2)
- (defconstant $TCPTerminate 3)
- (defconstant $TCPDataArrival 4)
- (defconstant $TCPUrgent 5)
- (defconstant $TCPICMPReceived 6)
-
- ;TCP termination reasons
- (defconstant $TCPRemoteAbort 2)
- (defconstant $TCPNetworkFailure 3)
- (defconstant $TCPSecPrecMismatch 4)
- (defconstant $TCPULPTimeoutTerminate 5)
- (defconstant $TCPULPAbort 6)
- (defconstant $TCPULPClose 7)
- (defconstant $TCPServiceError 8)
-
- ;ValidityFlags
- (defconstant $TCPtimeoutValue #x80)
- (defconstant $TCPtimeoutAction #x40)
- (defconstant $TCPtypeOfService #x20)
- (defconstant $TCPprecedence #x10)
-
- ;TOSFlags
- (defconstant $TCPlowDelay #x01)
- (defconstant $TCPthroughPut #x02)
- (defconstant $TCPreliability #x04)
-
- ; error codes
- (defconstant $TCPTimeout -23016)
-
- (eval-when (:compile-toplevel :load-toplevel :execute)
-
- (defrecord IPParamBlock
- (qLink pointer)
- (qType integer)
- (ioTrap integer)
- (ioCmdAddr pointer)
- (ioCompletion pointer)
- (ioResult integer)
- (ioNamePtr pointer)
- (ioVRefNum integer)
- (ioCRefNum integer)
- (csCode integer)
- (ourAddress unsigned-long)
- (ourNetMask unsigned-long))
-
- (defrecord tcpCreatePB
- (rcvBuff pointer)
- (rcvBuffLen longint) ; should be unsigned.
- (notifyProc pointer)
- (userDataPtr pointer))
-
- (defrecord tcpReleasePB
- (rcvBuff pointer)
- (rcvBuffLen longint))
-
- (defrecord tcpOpenPB
- (ulpTimeoutValue byte)
- (ulpTimeoutAction byte)
- (validityFlags byte)
- (commandTimeoutValue byte)
- (remoteHost unsigned-long)
- (remotePort integer)
- (localHost unsigned-long)
- (localPort integer)
- (tosFlags byte)
- (precedence byte)
- (dontFrag byte)
- (timeToLive byte)
- (security byte)
- (optionCnt byte)
- (options (string 39))
- (userDataPtr pointer))
-
- (defrecord tcpSendPB
- (ulpTimeoutValue byte)
- (ulpTimeoutAction byte)
- (validityFlags byte)
- (pushFlag byte)
- (urgentFlag byte)
- (fill byte)
- (wdsPtr pointer)
- (sendFree longint) ; unsigned
- (sendLength unsigned-integer)
- (userDataPtr pointer))
-
- (defrecord tcpReceivePB
- (commandTimeoutValue byte)
- (fill byte)
- (markFlag byte)
- (urgentFlag byte)
- (rcvBuff pointer)
- (rcvBuffLen unsigned-integer)
- (rdsPtr pointer)
- (rdsLength unsigned-integer)
- (secondTimeStamp unsigned-integer)
- (userDataPtr pointer))
-
- (defrecord tcpClosePB
- (ulpTimeoutValue byte)
- (ulpTimeoutAction byte)
- (validityFlags byte)
- (fill byte)
- (userDataPtr pointer))
-
- (defrecord tcpAbortPB
- (userDataPtr pointer))
-
- (defrecord tcpStatusPB
- (ulpTimeoutValue byte)
- (ulpTimeoutAction byte)
- (fill1 longint)
- (remoteHost unsigned-long)
- (remotePort unsigned-integer)
- (localHost unsigned-long)
- (localPort unsigned-integer)
- (tosFlags byte)
- (precedence byte)
- (connectionState byte)
- (fill2 byte)
- (sendWindow unsigned-integer)
- (rcvWindow unsigned-integer)
- (amtUnackedData unsigned-integer)
- (amtUnreadData unsigned-integer)
- (securityLevelPtr pointer)
- (sendUnacked longint)
- (sendNext longint)
- (congestionWindow longint)
- (rcvNext longint)
- (srtt longint)
- (lastRTT longint)
- (sendMaxSegSize longint)
- (connStatPtr pointer)
- (userDataPtr pointer))
-
- (defrecord tcpGlobalInfoPB
- (tcpParamPtr pointer)
- (tcpStatsPtr pointer)
- (tcpCDBTable pointer)
- (userDataPtr pointer))
-
- (defrecord tcpIOPB
- (qLink pointer)
- (qType integer)
- (ioTrap integer)
- (ioCmdAddr pointer)
- (ioCompletion pointer)
- (ioResult integer)
- (ioNamePtr pointer)
- (ioVRefNum integer)
- (ioCRefNum integer)
- (csCode integer)
- (StreamPtr pointer)
- (variant
- ((create tcpCreatePB))
- ((release tcpReleasePB))
- ((open tcpOpenPB))
- ((send tcpSendPB))
- ((receive tcpReceivePB))
- ((close tcpClosePB))
- ((abort tcpAbortPB))
- ((status tcpStatusPB))
- ((globalinfo tcpGlobalInfoPB))))
-
- (defrecord hostinfo
- (rtnCode longint)
- (cname (string 255))
- (addr1 unsigned-long)
- (addr2 unsigned-long)
- (addr3 unsigned-long)
- (addr4 unsigned-long)
- ;This is our own extension...
- (result integer))
-
- ) ;defrecord eval-when
-
- (defconstant $cacheFault -23042)
- (defconstant $tcpPBsize (record-length :tcpioPB))
-
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; MacTCP.Lisp
-
- (defparameter *service-name-number-alist*
- '(("echo" . 7)
- ("discard" . 9) ; sink null
- ("systat" . 11)
- ("daytime" . 13)
- ("netstat" . 15)
- ("ftp-data" . 20)
- ("ftp" . 21)
- ("telnet" . 23)
- ("smtp" . 25)
- ("time" . 37)
- ("name" . 32) ; (udp only)
- ("whois" . 43) ; usually to sri-nic
- ("domain" . 53)
- ("hostnames" . 101) ; usually to sri-nic
- ("sunrpc" . 111)
- ("rje" . 77)
- ("finger" . 79)
- ("link" . 87) ; ttylink
- ("supdup" . 95)
- ("iso-tsap" . 102)
- ;("x400" . 103) ; # ISO Mail
- ("dictionary" . 103)
- ("x400-snd" . 104)
- ("csnet-ns" . 105)
- ("pop" . 109)
- ("uucp-path" . 117)
- ("nntp" . 119)
- ("ntp" . 123)
- ("NeWS" . 144)
- ; UNIX specific services
- ;these are NOT officially assigned
- ("exec" . 512)
- ("login" . 513)
- ("shell" . 514)
- ("printer" . 515) ; spooler # experimental
- ("courier" . 530) ; rpc # experimental
- ("biff" . 512) ; (udp only) comsat
- ("who" . 513) ; (udp only)
- ("syslog" . 514) ; (udp only)
- ("talk" . 517) ; (udp only)
- ("route" . 520) ; (udp only)
- ("new-rwho" . 550) ; (udp only) # experimental
- ("rmonitor" . 560) ; (udp only) # experimental
- ("monitor" . 561) ; (udp only) # experimental
- ("ingreslock" . 1524)
- ("imap" . 143)))
-
- (defvar *tcp-driver-refnum* nil)
- (defvar %resolver-code% nil)
- (defvar %tcp-set-result-proc% nil)
- (defvar %hinfo-record% nil)
- (defvar *open-tcp-streams* nil)
-
- (def-load-pointers tcp ()
- (let* ((code '(#x225f ; spop a1
- #x584f ; addq #4,sp
- #x205f ; spop a0
- #x3168 #x0002 #x0114 ; move.w 2(a0),hostinfo.result(a0)
- #x4ed1)) ; jmp (a1)
- (codelen (length code)))
- (setq *tcp-driver-refnum* nil)
- (setq %resolver-code% nil)
- (setq %tcp-set-result-proc% (let ((ptr (#_NewPtr (+ codelen codelen))))
- (dotimes (i codelen ptr)
- (%put-word ptr (pop code) (+ i i)))))
- (setq %hinfo-record% (make-record :hostinfo))))
-
- (defun tcp-driver-refnum ()
- (or *tcp-driver-refnum*
- (with-pstrs ((name ".ipp"))
- (rlet ((pb hparamblockrec))
- (setf (rref pb hparamblockrec.ionameptr) name
- (rref pb hparamblockrec.iocompletion) (%null-ptr)
- (rref pb hparamblockrec.ioPermssn) 0)
- (#_open :errchk pb)
- (setq *tcp-driver-refnum* (rref pb hparamblockrec.ioRefNum))))))
-
- (defun %tcp-control (pb code &optional ignore-error-p ignore-timeout)
- (setf (rref pb tcpioPB.csCode) code
- (rref pb tcpioPB.ioCompletion) (%null-ptr))
- (let* ((err nil))
- (progn
- (loop
- (when (eql (setq err (#_control :async pb)) 0)
- (let* ((*interrupt-level* 0))
- (while (> (setq err (rref pb tcpioPB.ioResult)) 0))))
- (return))
- (unless (or ignore-error-p (eql err 0)
- (and ignore-timeout (eql err $TCPTimeout)))
- (%tcp-err-disp err))
- err)))
-
- ;Timeout should be an arg...
- (defun tcp-active-open (address port &optional (bufsize 8192) notify-routine)
- (let ((pb nil))
- (unwind-protect
- (progn
- (setq pb (#_NewPtr :Clear :errchk (+ bufsize $tcpPBSize)))
- (%tcp-create pb (%inc-ptr pb $tcpPBSize) bufsize notify-routine)
- (%tcp-active-open pb address port)
- (prog1 pb (setq pb nil)))
- (when pb
- (unless (%null-ptr-p (rref pb tcpioPB.streamPtr))
- (setf (rref pb tcpioPB.csCode) $TCPRelease)
- (#_Control pb))
- (#_DisposPtr pb)))))
-
- (defun %tcp-create (pb RcvBuff RcvBuffLen notifyProc)
- (setf (rref pb tcpioPB.ioCRefNum) (tcp-driver-refnum)
- (rref pb tcpioPB.create.RcvBuff) RcvBuff
- (rref pb tcpioPB.create.RcvBuffLen) RcvBuffLen
- (rref pb tcpioPB.create.notifyProc) (or notifyProc (%null-ptr)))
- (%tcp-control pb $TCPCreate))
-
- ; Wait for a connection (from any host, port) to us.
- (defun %tcp-passive-open (pb port &optional (timeout 30))
- (setf (rref pb tcpioPB.open.validityFlags) 0
- (rref pb tcpioPB.open.commandTimeoutValue) timeout
- (rref pb tcpioPB.open.localPort) port
- (rref pb tcpioPB.open.optionCnt) 0
- (rref pb tcpioPB.open.remoteHost) 0
- (rref pb tcpioPB.open.remotePort) 0
- (rref pb tcpioPB.open.timeToLive) 0) ; time-to-live = 60 hops
- (%tcp-control pb $TCPPassiveOpen nil t))
-
- (defun %tcp-active-open (pb address port)
- (setf (rref pb tcpioPB.open.validityFlags) 0 ; let timeouts, etc default.
- (rref pb tcpioPB.open.localPort) 0 ; default our port
- (rref pb tcpioPB.open.timeToLive) 0 ; time-to-live = 60 hops
- (rref pb tcpioPB.open.optionCnt) 0 ; What are TCP options?
- (rref pb tcpioPB.open.localHost) (%tcp-getaddr)
- (rref pb tcpioPB.open.remoteHost) address
- (rref pb tcpioPB.open.remotePort) port)
- (%tcp-control pb $TCPActiveOpen))
-
- (defun %tcp-getaddr ()
- (rlet ((pb :IPParamBlock))
- (setf (rref pb IPParamBlock.ioCRefNum) (tcp-driver-refnum))
- (%tcp-control pb $ipctlGetAddr)
- (values (rref pb IPParamBlock.ourAddress)
- (rref pb IPParamBlock.ourNetMask))))
-
- (defun %tcp-send (pb bufptr buflen push-p)
- (when (%i> buflen #xFFFF) (report-bad-arg buflen '(integer 0 #xFFFF)))
- (%stack-block ((wds 8))
- (%put-word wds buflen 0)
- (%put-ptr wds bufptr 2)
- (%put-word wds 0 6)
- (setf (rref pb tcpioPB.send.wdsPtr) wds
- (rref pb tcpioPB.send.pushFlag) (if push-p -1 0)
- (rref pb tcpioPB.send.urgentFlag) 0
- (rref pb tcpioPB.send.validityFlags) 0)
- (%tcp-control pb $TCPSend)))
-
- (defun tcp-send (pb string push-p)
- (if (<= (length string) 1024)
- (with-cstr (buf string)
- (%tcp-send pb buf (length string) push-p))
- (multiple-value-bind (sstr start end) (get-sstring string)
- (declare (type fixnum start end))
- (%stack-block ((buf 1024))
- ; This code is untested because nobody calls TCP-SEND
- (let ((sstr-ptr (%null-ptr))
- len)
- (declare (dynamic-extent sstr-ptr)
- (type macptr sstr-ptr)
- (type fixnum len))
- (loop
- (setq len (- end start))
- (if (<= len 0) (return))
- (if (< 1024 len) (setq len 1024))
- (without-interrupts
- (%address-to-macptr sstr sstr-ptr)
- (#_BlockMove (%inc-ptr sstr-ptr (+ 7 start)) buf len))
- (setq start (+ start 1024))
- (%tcp-send pb buf len (and push-p (>= start end)))))))))
-
- (defun %address-to-macptr (address &optional (macptr (%null-ptr)))
- (%setf-macptr macptr (%int-to-ptr (%address-of address))))
-
- (defun %tcp-rcv (pb ptr len timeout)
- (setf (rref pb tcpioPB.Receive.commandTimeoutValue) timeout
- (rref pb tcpioPB.Receive.rcvBuff) ptr
- (rref pb tcpioPB.Receive.rcvBuffLen) (require-type len '(integer 0 #xFFFF)))
- (%tcp-control pb $TCPRcv)
- (rref pb tcpioPB.Receive.rcvBuffLen))
-
- (defun %tcp-bfrreturn (pb rds)
- (setf (rref pb tcpioPB.Receive.rdsPtr) rds)
- (%tcp-control pb $TCPRcvBfrReturn))
-
- (defun %tcp-nocopyrcv (pb rdsptr rdslen timeout)
- (setf (rref pb tcpioPB.Receive.commandTimeoutValue) timeout
- (rref pb tcpioPB.Receive.rdsPtr) rdsptr
- (rref pb tcpioPB.Receive.rdsLength) (require-type rdslen '(integer 0 #xFFFF)))
- (%tcp-control pb $TCPNoCopyRcv))
-
- (defun %tcp-close (pb)
- (setf (rref pb tcpioPB.close.validityFlags) 0)
- (%tcp-control pb $TCPClose))
-
- (defun %tcp-abort (pb)
- (%tcp-control pb $TCPAbort))
-
- (defun %tcp-release (pb) ; This does a TCPAbort...
- (unless (%null-ptr-p (rref pb tcpioPB.StreamPtr))
- (%tcp-control pb $TCPRelease)
- (setf (rref pb tcpioPB.StreamPtr) (%null-ptr)))
- nil)
-
- (defun tcp-release (pb)
- (unless (%null-ptr-p pb)
- (%tcp-release pb)
- (%setf-macptr pb (%null-ptr))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defconstant $openresolver 1)
- (defconstant $closeresolver 2)
- (defconstant $strtoaddr 3)
- (defconstant $addrtostr 4)
- (defconstant $enumcache 5)
- (defconstant $addrtoname 6)
-
-
- (defun find-system-folder ()
- (let* ((wdrefnum
- (rlet ((info :SysEnvRec))
- (#_SysEnvirons :errchk 1 info)
- (rref info SysEnvRec.sysVRefNum))))
- (rlet ((pb :hparamblockrec)
- (nameptr :str31))
- (setf (rref pb :hparamblockrec.ioWDIndex) 0
- (rref pb :hparamblockrec.ionameptr) nameptr
- (rref pb :hparamblockrec.ioVrefNum) wdrefnum
- (rref pb :hparamblockrec.ioWDProcID) 0)
- (if (eql #$noErr (#_GetWDInfo pb))
- (values (rref pb :hparamblockrec.ioWDVrefNum)
- (rref pb :hparamblockrec.ioWDDirID))
- (values nil nil)))))
-
- (defun find-control-panels-folder ()
- (let* ((vrefnum nil)
- (dirID nil))
- (when (logbitp #$gestaltFindFolderPresent
- (or (ccl::gestalt #$gestaltFindFolderAttr) 0))
- (rlet ((vrefnumP :signed-integer)
- (diridP :signed-long))
- (when (eql #$noErr
- (#_FindFolder
- #$kOnSystemDisk
- #$kControlPanelFolderType
- #$kDontCreateFolder
- vRefNumP
- dirIDP))
- (setq vrefnum (%get-signed-word vrefnump)
- dirid (%get-signed-long diriDP)))))
- (values vrefnum dirID)))
-
- (defun %load-resolver-code ()
- (or %resolver-code%
- (multiple-value-bind (sysvrefnum sysdirid) (find-system-folder)
- (multiple-value-bind (cpvrefnum cpdirid) (find-control-panels-folder)
- (setq %resolver-code%
- (or
- (%find-dnr "cdev" "ztcp" cpvrefnum sysdirid) ; 1.1
- (%find-dnr "cdev" "mtcp" sysvrefnum sysdirid) ; 1.0.x in system folder
- (%find-dnr "cdev" "mtcp" cpvrefnum cpdirid) ; 1.0.x in control panels folder
- (error "Can't load MacTCP Domain Name Resolver")))))))
-
- (defun %find-dnr (type creator vrefnum dirid)
- ; Returns detached handle to DNRP resource or NIL.
- (when vrefnum
- (rlet ((name :str255)
- (pb :hparamblockrec))
- (setf (rref pb :hparamblockrec.ionameptr) name
- (rref pb :hparamblockrec.iovrefnum) vrefnum
- (rref pb :hparamblockrec.ioDirID) dirid
- (rref pb :hparamblockrec.ioFDirIndex) 1)
- (do* ()
- ((not (eql #$noErr (#_HGetFinfo pb))) nil)
- (if (and (string= (rref pb :hparamblockrec.ioFlFndrInfo.fdType) type)
- (string= (rref pb :hparamblockrec.ioFlFndrInfo.fdCreator) creator))
- (let* ((refnum (#_HOpenResFile vrefnum dirid name #$fsRdPerm)))
- (if (eql refnum -1)
- (return nil)
- (unwind-protect
- (let* ((dnrp (#_Get1IndResource "dnrp" 1)))
- (unless (%null-ptr-p dnrp)
- (#_DetachResource dnrp)
- (#_CloseResFile refnum)
- (#_HLock dnrp)
- (%setf-macptr dnrp (%get-ptr dnrp))
- (#_StripAddress dnrp)
- (return dnrp)))
- (#_CloseResFile refnum))))
- (progn
- (setf (rref pb :hparamblockrec.ioDirID) dirid) ; clobbered by _HGetFinfo
- (incf (rref pb :hparamblockrec.ioFDirIndex))))))))
-
-
- (defun %open-resolver (&optional hosts-file)
- (unless %resolver-code%
- (let* ((err -1))
- (unwind-protect
- (progn
- (%load-resolver-code)
- (with-cstr (np (or hosts-file ""))
- (when (null hosts-file) (%setf-macptr np (%null-ptr)))
- (setq err (ff-call %resolver-code% :ptr np :long $openresolver :d0)))
- (unless (eql err 0) (%tcp-err-disp err)))
- (unless (eql err 0) (%dispose-resolver))))))
-
- (defun %close-resolver ()
- (when %resolver-code%
- (ff-call %resolver-code% :long $closeresolver :d0)
- (%dispose-resolver)))
-
- (defun %dispose-resolver ()
- (when %resolver-code%
- (let ((code %resolver-code%))
- (setq %resolver-code% nil)
- (%setf-macptr code (#_RecoverHandle code))
- (#_HUnlock code)
- (#_DisposHandle :errchk code))))
-
- (defun %tcp-enum-cache (resultproc userdataptr)
- (%open-resolver)
- (ff-call %resolver-code% :ptr userdataptr :ptr resultproc :long $enumcache :d0))
-
- (defun %tcp-addr-to-name (addr hostinfoptr resultproc userdataptr)
- (%open-resolver)
- (ff-call %resolver-code%
- :ptr (or userdataptr (%null-ptr))
- :ptr (or resultproc (%null-ptr))
- :ptr hostinfoptr
- :long addr
- :long $addrtoname
- :d0))
-
- (defun tcp-addr-to-name (addr)
- (setf (rref %hinfo-record% hostinfo.result) 1)
- (let ((err (%tcp-addr-to-name addr %hinfo-record% %tcp-set-result-proc% nil)))
- (when (eq err $cacheFault)
- (while (eq (setq err (rref %hinfo-record% hostinfo.result)) 1)))
- err))
-
- (defun %tcp-str-to-addr (host-name hostinfoptr resultproc userdataptr)
- (%open-resolver)
- (with-cstr (np host-name)
- (ff-call %resolver-code%
- :ptr (or userdataptr (%null-ptr))
- :ptr (or resultproc (%null-ptr))
- :ptr hostinfoptr
- :ptr np
- :long $strtoaddr
- :d0)))
-
- (defun tcp-str-to-addr (host-name)
- (setf (rref %hinfo-record% hostinfo.result) 1)
- (let ((err (%tcp-str-to-addr host-name %hinfo-record% %tcp-set-result-proc% nil)))
- (when (eq err $cacheFault)
- (while (eq (setq err (rref %hinfo-record% hostinfo.result)) 1)))
- err))
-
- #|
- (defun %tcp-addr-to-str (addr strptr)
- (%open-resolver)
- (ff-call %resolver-code% :ptr strptr :long addr :long $addrtostr :d0))
- (defun tcp-addr-to-str (addr)
- (%stack-block ((str 16))
- (%tcp-addr-to-str addr str)
- (%get-cstring str)))
- |#
-
- (defun tcp-addr-to-str (addr)
- (format nil "~D.~D.~D.~D"
- (ldb (byte 8 24) addr)
- (ldb (byte 8 16) addr)
- (ldb (byte 8 8) addr)
- (ldb (byte 8 0) addr)))
-
- (defun tcp-host-address (host-name)
- (if (integerp host-name)
- host-name
- (if (and (stringp host-name) (eql 0 (length host-name)))
- (values (%tcp-getaddr))
- (let ((err (tcp-str-to-addr host-name)))
- (unless (eql err 0) (%tcp-err-disp err))
- (rref %hinfo-record% hostinfo.addr1)))))
-
- (defun tcp-host-cname (host-address)
- (if (integerp host-address)
- (setq host-address (tcp-host-address host-address)))
- (let ((err (tcp-addr-to-name host-address)))
- (unless (eql err 0) (%tcp-err-disp err))
- ;(break "foo")
- (%get-cstring %hinfo-record% 4)))
-
- (defun tcp-host-info (host-name)
- (when (integerp host-name)
- (setq host-name (tcp-addr-to-str host-name)))
- (let ((err (tcp-str-to-addr host-name)))
- (unless (eql err 0) (%tcp-err-disp err))
- (values (%get-cstring %hinfo-record% 4)
- (rref %hinfo-record% hostinfo.addr1)
- (rref %hinfo-record% hostinfo.addr2)
- (rref %hinfo-record% hostinfo.addr3)
- (rref %hinfo-record% hostinfo.addr4))))
-
- (defparameter *tcp-error-strings*
- '((-23000 . "Bad network configuration")
- (-23001 . "bad IP configuration")
- (-23002 . "Missing IP or LAP configuration")
- (-23003 . "Error loading MacTCP")
- ;#define ipBadAddr -23004 /* error in getting address */
- (-23005 . "TCP connection closing")
- ;#define invalidLength -23006
- (-23007 . "Request conflicts with existing connection")
- (-23008 . "Connection does not exist")
- (-23009 . "Insufficient resources to perform TCP request")
- ;#define invalidStreamPtr -23010
- ;#define streamAlreadyOpen -23011
- (-23012 . "Connection terminated")
- ;#define invalidBufPtr -23013
- ;#define invalidRDS -23014
- ;#define invalidWDS -23014
- (-23015 . "TCP open failed")
- (-23016 . "TCP command timeout")
- ;#define duplicateSocket -23017
- ;#define ipDontFragErr -23032 /* Packet too large to send w/o fragmenting */
- (-23033 . "Destination host is not responding")
- ;#define ipNoFragMemErr -23036 /* no memory to send fragmented pkt */
- ;#define ipRouteErr -23037 /* can't route packet off-net */
- (-23041 . "Syntax error in host name")
- ;#define cacheFault -23042
- ;#define noResultProc -23043
- (-23044 . "No name server can be found for the specified domain name")
- (-23045 . "Domain name does not exist")
- (-23046 . "None of the known name servers are responding")
- (-23047 . "The domain name server has returned an error")
- ;#define outOfMemory -23048
- ))
-
-
-
- (defun %tcp-err-disp (errno)
- (let ((err (assq (setq errno (%word-to-int errno)) *tcp-error-strings*))
- (error-fn #'error)) ; want to tail-call...
- (declare (type list err))
- (if err (funcall error-fn (cdr err)) (%err-disp errno))))
-
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
- (defclass tcp-stream (input-stream output-stream)
- ((conn :initform nil)))
-
- (defclass binary-tcp-stream (tcp-stream io-binary-stream)
- ())
-
- (defmethod initialize-instance ((s binary-tcp-stream)
- &key (element-type '(unsigned-byte 8) element-type-p))
- (unless (or (not element-type-p)
- (eq element-type 'unsigned-byte) ; Shorthand ...
- (and (subtypep element-type '(unsigned-byte 8))
- (subtypep '(unsigned-byte 8) element-type)))
- (error "element-type ~S not supported." element-type))
- ; no supertype cares about :element-type
- (call-next-method))
-
- (defstruct conn ; Don't bother doing slot-value for every little thing...
- pb
- write-buffer
- write-bufsize
- write-count
- read-timeout
- untyi-char
- rds
- rds-entries
- rds-offset ; offset in rds to next buffer
- read-count
- read-bufptr)
-
- (defmethod print-object ((self tcp-stream) stream)
- (let* ((type (type-of self))
- (conn (slot-value self 'conn))
- (pb (when conn (conn-pb conn)))
- (err (and pb (%tcp-control pb $TCPStatus t))))
- (case err
- ((0)
- (format stream "#<~S ~S -> ~A@~A>"
- type
- (tcp-state-name (rref pb tcpioPB.status.connectionState))
- (tcp-service-name (rref pb tcpioPB.status.remotePort))
- (tcp-addr-to-str (rref pb tcpioPB.status.remoteHost))))
- ((nil -23008) ; connection doesn't exist.
- (format stream "#<~S ~S>" type :closed))
- (t (%tcp-err-disp err)))))
-
- (defun tcp-connection-state (stream)
- (let* ((conn (slot-value stream 'conn))
- (pb (and conn (conn-pb conn))))
- (if (and pb (eq 0 (%tcp-control pb $TCPStatus t)))
- (rref pb tcpioPB.status.connectionState)
- 0)))
-
- (defun tcp-state-name (state)
- (or (cdr (assq state
- '((0 . :closed)
- (2 . :listen)
- (4 . :syn-received)
- (6 . :syn-sent)
- (8 . :established)
- (10 . :fin-wait-1)
- (12 . :fin-wait-2)
- (14 . :close-wait)
- (16 . :closing)
- (18 . :closing-last-ack)
- (20 . :closing-time-ack))))
- state))
-
- (defun tcp-service-name (port)
- (or (car (rassoc port *service-name-number-alist*))
- port))
-
- (defun tcp-stream-conn (s)
- (or (slot-value s 'conn) (error "~S is closed" s)))
-
- (defmethod stream-tyo ((s tcp-stream) char &aux (conn (tcp-stream-conn s)))
- (without-interrupts
- (let* ((count (conn-write-count conn)))
- (when (eq count (conn-write-bufsize conn))
- (tcp-stream-force-output conn nil)
- (setq count (conn-write-count conn)))
- (setf (conn-write-count conn) (1+ count))
- (ccl:%put-byte (conn-write-buffer conn) (char-code char) count))))
-
- (defmethod stream-force-output ((s tcp-stream))
- (tcp-stream-force-output (tcp-stream-conn s) t))
-
- (defun tcp-stream-force-output (conn push-p)
- (without-interrupts
- (unless (eql (conn-write-count conn) 0)
- (%tcp-send (conn-pb conn) (conn-write-buffer conn) (conn-write-count conn) push-p))
- (setf (conn-write-count conn) 0)))
-
- (defmethod stream-write-vector ((s binary-tcp-stream) v start end)
- (locally
- (declare (fixnum start end))
- (multiple-value-bind (vector offset) (array-data-and-offset v)
- (declare (fixnum offset))
- (setq start (+ start offset))
- (do* ((conn (tcp-stream-conn s))
- (writebuf (conn-write-buffer conn))
- (bufsize (conn-write-bufsize conn))
- (length (- (+ end offset ) start) (- length room-in-buffer))
- (bufpos (conn-write-count conn) 0)
- (room-in-buffer (- bufsize bufpos) bufsize))
- ((<= length room-in-buffer)
- (dotimes (i length (progn (incf (conn-write-count conn) length) (tcp-stream-force-output conn t)))
- (ccl::%put-byte writebuf (ccl::uvref vector start) bufpos)
- (setq start (1+ start) bufpos (1+ bufpos))))
- (declare (fixnum length bufpos bufsize room-in-buffer))
- (dotimes (i room-in-buffer)
- (ccl::%put-byte writebuf (ccl::uvref vector start) bufpos)
- (setq start (1+ start) bufpos (1+ bufpos)))
- (setf (conn-write-count conn) bufsize)
- (tcp-stream-force-output conn t)))))
-
- (defmethod stream-read-vector ((s binary-tcp-stream) v start end)
- (locally
- (declare (fixnum start end))
- (multiple-value-bind (vector offset) (array-data-and-offset v)
- (declare (fixnum offset))
- (setq start (+ start offset))
- (let* ((length (- (+ end offset ) start))
- (conn (tcp-stream-conn s))
- (untyi-char (conn-untyi-char conn)))
- (declare (fixnum length))
- (if (and (> length 0) untyi-char)
- (progn
- (setf (ccl::uvref vector start) (char-code untyi-char)
- (conn-untyi-char conn) nil
- start (1+ start)
- length (1- length))))
- (do* ((pb (conn-pb conn))
- (rds (conn-rds conn)))
- ((zerop length))
- (when (eql (conn-read-count conn) 0)
- (%tcp-nocopyrcv pb rds (conn-rds-entries conn) (conn-read-timeout conn))
- (when (eql 0 (setf (conn-read-count conn) (ccl:%get-word rds)))
- (tcp-stream-bfr-return conn)
- (when (tcp-stream-eofp conn) ;Can't get a character.
- (return-from stream-read-vector nil))
- (error "Can't read a character from ~S" s))
- (ccl:%setf-macptr (conn-read-bufptr conn) (ccl:%get-ptr rds 2))
- (setf (conn-rds-offset conn) 6))
- (setf (ccl::uvref vector start) (ccl::%get-unsigned-byte (conn-read-bufptr conn)))
- (incf start)
- (ccl:%incf-ptr (conn-read-bufptr conn))
- (decf length)
- (when (eql (setf (conn-read-count conn) (1- (conn-read-count conn))) 0)
- (let* ((rds (conn-rds conn))
- (nextbuf (conn-rds-offset conn))
- (bufptr (conn-read-bufptr conn)))
- (if (eql (setf (conn-read-count conn) (ccl:%get-word rds nextbuf)) 0)
- (tcp-stream-bfr-return conn)
- (progn
- (ccl:%setf-macptr bufptr (ccl:%get-ptr rds (+ nextbuf 2)))
- (setf (conn-rds-offset conn) (+ nextbuf 6)))))))))))
-
- (defmethod stream-tyi ((s tcp-stream) &aux (conn (tcp-stream-conn s)))
- (without-interrupts
- (if (conn-untyi-char conn)
- (prog1 (conn-untyi-char conn) (setf (conn-untyi-char conn) nil))
- (progn
- (when (eql (conn-read-count conn) 0)
- (when (tcp-stream-eofp conn)
- (return-from stream-tyi nil))
- (let* ((pb (conn-pb conn))
- (rds (conn-rds conn)))
- (%tcp-nocopyrcv pb rds (conn-rds-entries conn) (conn-read-timeout conn))
- (when (eql 0 (setf (conn-read-count conn) (ccl:%get-word rds)))
- (tcp-stream-bfr-return conn)
- (when (tcp-stream-eofp conn)
- (return-from stream-tyi nil))
- (error "Can't read a character from ~S" s))
- (ccl:%setf-macptr (conn-read-bufptr conn) (ccl:%get-ptr rds 2))
- (setf (conn-rds-offset conn) 6)))
- (prog1 (code-char (ccl:%get-byte (conn-read-bufptr conn)))
- (ccl:%incf-ptr (conn-read-bufptr conn))
- (when (eql (setf (conn-read-count conn) (1- (conn-read-count conn))) 0)
- (let* ((rds (conn-rds conn))
- (nextbuf (conn-rds-offset conn))
- (bufptr (conn-read-bufptr conn)))
- (if (eql (setf (conn-read-count conn) (ccl:%get-word rds nextbuf)) 0)
- (tcp-stream-bfr-return conn)
- (progn
- (ccl:%setf-macptr bufptr (ccl:%get-ptr rds (+ nextbuf 2)))
- (setf (conn-rds-offset conn) (+ nextbuf 6)))))))))))
-
-
- (defmethod stream-read-byte ((s binary-tcp-stream))
- (let* ((char (stream-tyi s)))
- (if char
- (locally (declare (type character char)) (char-code char)))))
-
- (defmethod stream-write-byte ((s binary-tcp-stream) b)
- (stream-tyo s (code-char (logand #xff b))))
-
- (defun tcp-stream-bfr-return (conn)
- (ccl:%setf-macptr (conn-read-bufptr conn) (ccl:%null-ptr))
- (setf (conn-read-count conn) 0) ; Usually redundant except in clear-input..
- (%tcp-bfrreturn (conn-pb conn) (conn-rds conn)))
-
- (defmethod stream-listen ((s tcp-stream) &aux (conn (tcp-stream-conn s)))
- (or (conn-untyi-char conn)
- (not (eql (conn-read-count conn) 0))
- (let ((pb (conn-pb conn)))
- (and (eql (%tcp-control pb $TCPStatus T) 0)
- (> (rref pb tcpioPB.status.amtUnreadData) 0)))))
-
-
- (defmethod stream-untyi ((s tcp-stream) char)
- (setf (conn-untyi-char (tcp-stream-conn s)) char))
-
- (defmethod stream-eofp ((s tcp-stream))
- (let* ((conn (tcp-stream-conn s)))
- (and (null (conn-untyi-char conn))
- (eql (conn-read-count conn) 0)
- (tcp-stream-eofp conn))))
-
- (defun tcp-stream-eofp (conn)
- (let* ((pb (conn-pb conn))
- (err (%tcp-control pb $TCPStatus t)))
- (or (eq err -23008) ; connection doesn't exist
- (if (eql err 0)
- (memq (rref pb tcpioPB.status.connectionState)
- '(0 ; Closed
- 14 ; Close Wait
- 16 ; Closing
- 18 ; Last Ack
- 20)) ; Time Wait
- (%tcp-err-disp err)))))
-
- ;Kind of bogus, but most of the protocols don't depend on a reliable close anyhow...
- (defmethod stream-close ((s tcp-stream) &aux (conn (slot-value s 'conn)))
- (when conn
- (stream-clear-input s)
- (ignore-errors (tcp-stream-force-output s t)) ; Ok if fails (bogus)
- (let ((pb (conn-pb conn)))
- (setf (rref pb tcpioPB.close.validityFlags) 0)
- (%tcp-control pb $TCPClose T) ; Ok if fails (bogus)
- (%tcp-release pb)
- (#_DisposPtr pb)
- (setf (slot-value s 'conn) nil))
- (setq *open-tcp-streams* (delete s *open-tcp-streams* :test #'eq)))
- (call-next-method))
-
- (defmethod stream-abort ((s tcp-stream)) ;called before stream-close for abort.
- (stream-clear-input s)
- (%tcp-control (conn-pb (tcp-stream-conn s)) $tcpAbort T)) ; Ok if fails
-
- (defmethod stream-clear-input ((s tcp-stream))
- (let ((conn (tcp-stream-conn s)))
- (setf (conn-untyi-char conn) nil)
- (unless (eql 0 (conn-read-count conn))
- (tcp-stream-bfr-return conn))))
-
- (defmethod initialize-instance ((s tcp-stream) &key
- host
- port
- (tcpbufsize 8192)
- (rdsentries 6)
- (writebufsize 1024)
- notify-proc
- (commandtimeout 30))
- (call-next-method)
- (let (pb)
- (unless (integerp port)
- (setq port (or (cdr (assoc (require-type port '(or string symbol))
- *service-name-number-alist* :test #'string-equal))
- (error "Unknown port ~S" port))))
- (when host
- (setq host (tcp-host-address host)))
- (unwind-protect
- (progn
- (setq pb (#_NewPtr :clear :errchk (+ $tcpPBSize tcpbufsize writebufsize (+ (* 6 rdsentries) 2))))
- (%tcp-create pb (ccl:%inc-ptr pb $tcpPBSize) tcpbufsize notify-proc)
- (if host
- (%tcp-active-open pb host port)
- (%tcp-passive-open pb port commandtimeout))
- (setf (slot-value s 'conn)
- (make-conn :pb pb
- :write-buffer (ccl:%inc-ptr pb (+ $tcpPBSize tcpbufsize))
- :write-bufsize writebufsize
- :write-count 0
- :read-timeout commandtimeout
- :untyi-char nil
- :rds (ccl:%inc-ptr pb (+ $tcpPBSize tcpbufsize writebufsize))
- :rds-entries rdsentries
- :rds-offset 0
- :read-count 0
- :read-bufptr (ccl:%null-ptr)))
- (setq pb nil)
- (push s *open-tcp-streams*)
- s)
- (when pb
- (unless (ccl:%null-ptr-p (rref pb tcpioPB.StreamPtr))
- (%tcp-control pb $TCPRelease T))
- (#_DisposPtr pb)))))
-
- (defun open-tcp-stream (host port &key (element-type 'character)
- (tcpbufsize 8192)
- (rdsentries 6)
- (writebufsize 1024)
- notify-proc
- (commandtimeout 30))
- (if (subtypep element-type 'character)
- (make-instance 'tcp-stream
- :host host :port port
- :tcpbufsize tcpbufsize
- :rdsentries rdsentries
- :writebufsize writebufsize
- :notify-proc notify-proc
- :commandtimeout commandtimeout)
- (make-instance 'binary-tcp-stream
- :element-type element-type
- :host host :port port
- :tcpbufsize tcpbufsize
- :rdsentries rdsentries
- :writebufsize writebufsize
- :notify-proc notify-proc
- :commandtimeout commandtimeout)))
-
-
- ;;Useful little functions: read & write CRLF-terminated lines from a "clear text"
- ;; connection.
- (defun telnet-read-line (stream)
- "Read a CRLF-terminated line"
- (unless (ccl:stream-eofp stream)
- (let ((line (Make-Array 10 :Element-Type 'Character :Adjustable T :Fill-Pointer 0))
- (char nil))
- (do () ((or (null (setq char (ccl:stream-tyi stream)))
- (and (eq char #\CR) (eq (ccl:stream-peek stream) #\LF)))
- (when char (ccl:stream-tyi stream))
- (values line (null char)))
- (vector-push-extend char line)))))
-
- (defun telnet-write-line (stream string &rest args)
- "Write a CRLF-terminated line"
- (declare (dynamic-extent args))
- (apply #'format stream string args)
- (write-char #\CR stream)
- (write-char #\LF stream)
- (force-output stream))
-
- ;; Before quitting ...
-
- (defun cleanup-after-mactcp ()
- (do* ()
- ((null *open-tcp-streams*))
- (close (car *open-tcp-streams*)))
- (%close-resolver))
-
- (pushnew #'cleanup-after-mactcp *lisp-cleanup-functions* :key #'function-name :test #'eq)
-